
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>


#define M_AppName       "batchfilecmd"			/* App name */

char    g_abPatten[MAX_PATH] = {0};				/* File extention */
char    g_abUserCmd[MAX_PATH] = {0};			/* User command */
char    g_abCmdRun[MAX_PATH] = {0};				/* Command to run */


void bfcProcessOneFile(char *pPath, char *pFileName);


/*******************************************************************//**
 *@par  Description: 
        Recursively find files.
 *@param [in]   pPath 	Current directory.
 *@return       void
 *@par  Change Log: 
 *@details -# 2013/12/24, Created by elepatria.
 ***********************************************************************/
void bfcTravalDir(char *pPath)
{
    char abPathFind[MAX_PATH];
    char abFileFound[MAX_PATH];
    char *pFileName;
    char *pStart;

    WIN32_FIND_DATA FindFileData;
	
	if (!pPath)
		return;
		
    strcpy(abPathFind, pPath);
    strcat(abPathFind, "\\*.*");

    HANDLE hFind = FindFirstFile(abPathFind, &FindFileData);
    if(INVALID_HANDLE_VALUE == hFind)
        return;

    while(TRUE)
    {
        pFileName = FindFileData.cFileName;
        if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
        {
            if(pFileName[0] != '.')
            {
                strcpy(abFileFound, pPath);
                strcat(abFileFound, "\\");
                strcat(abFileFound, pFileName);
                bfcTravalDir(abFileFound);
            }
        }
        else
        {
            bfcProcessOneFile(pPath, pFileName);
        }

        if(!FindNextFile(hFind, &FindFileData))
            break;
    }
    
    bfcProcessOneFile(pPath, NULL);
    FindClose(hFind);
}


/*******************************************************************//**
 *@par  Description: 
        Printf help.
 *@param [in]   void.
 *@return       void.
 *@par  Change Log: 
 *@details -# 2013/12/24, Created by elepatria.
 ***********************************************************************/
void bfcPrintHelp(void)
{
    char    *pUsage =
    "Version: 0.1 (han.elepatria)\n"
    "Usage: "M_AppName" FileExt Path \"command\"\n"
    "\n"
    "Batch operate file with user command.\n"
    "\n"
    "  command Format: \n"
    "  $F - Full file name, include path.\n"
    "  $p - Full path name only\n"
    "  $f - file name only\n"
    "\n"
    "For example: "M_AppName" .cpp c:\ \"del /F /Q $F\" \n";

    printf(pUsage);
}

/*******************************************************************//**
 *@par  Description: 
        Match one file.
 *@param [in]   pPath:		File path. 
 *@param [in]   pFileName: 	Filename.
 *@return       void.
 *@par  Change Log: 
 *@details -# 2013/12/24, Created by elepatria.
 ***********************************************************************/
int bfcMatchFile(char *pFileName)
{
	char *pFind;
	
	pFind = strstr(pFileName, g_abPatten);
    if (!pFind)
        return 0;

    if (pFind+strlen(g_abPatten) != pFileName+strlen(pFileName))
        return 0;
        
   	return 1;
}

/*******************************************************************//**
 *@par  Description: 
        Process one file.
 *@param [in]   pPath:		File path. 
 *@param [in]   pFileName: 	Filename.
 *@return       void.
 *@par  Change Log: 
 *@details -# 2013/12/24, Created by elepatria.
 ***********************************************************************/
void bfcProcessOneFile(char *pPath, char *pFileName)
{
    char    abFullName[MAX_PATH];
    char    *pFind, *pCmd, *pCmdRun;
    
    if (!pFileName)
    	return;
   	
   	if (!bfcMatchFile(pFileName))
   		return;
   		
    strcpy(abFullName, pPath);
    strcat(abFullName, "\\");
    strcat(abFullName, pFileName);

    pCmd = g_abUserCmd;
    pCmdRun = g_abCmdRun;
    memset(g_abCmdRun, 0, MAX_PATH);
    while(*pCmd)
    {
        if (*pCmd == '$')
        {
            pCmd++;
            switch (*pCmd)
            {
                case 'F':
                    strcat(g_abCmdRun, abFullName);
                    break;
                case 'f':
                    strcat(g_abCmdRun, pFileName);
                    break;
                case 'p':
                    strcat(g_abCmdRun, pPath);
                    break;
                default:
                    break;
                pCmdRun = g_abCmdRun+strlen(g_abCmdRun);
            }
            
            pCmd++;
            continue;
        }
        
        *pCmdRun++ = *pCmd++;
    }
    
    system(g_abCmdRun);
}


int main(int argc, char *argv[])
{
    int  	i;
    char    *pExt = argv[1];
    char    *pRootDir = argv[2];
    
    if (argc != 4)
    {
    	bfcPrintHelp();
        return 1;
    }
    
    strcpy(g_abPatten, pExt);
    strcpy(g_abUserCmd, argv[3]);
    
    bfcTravalDir(pRootDir);

	return 0;
}

